/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

#include <stdlib.h>
#include <string.h>
#include <aos/aos.h>
#ifdef AOS_COMP_CLI
#include "aos/cli.h"
#endif
#include "aos/ble.h"
#include "app_main.h"
#include "app_init.h"
#include "pin_name.h"
#include <yoc/bas.h>
#include <yoc/hids.h>
#include <yoc/bas.h>
#include <yoc/dis.h>
#include "alertor_server.h"
#include <yoc/ota_server.h>
#include "board_config.h"

#define TAG  "DEMO"

#define DEVICE_NAME "YoC-Alertor"
#define DEVICE_ADDR {0xCC,0x3B,0xE3,0x88,0xBA,0xC0}
extern int bt_passkey_set(unsigned int passkey);
extern const char *bt_hex_real(const void *buf, size_t len);

static int16_t g_conn_hanlde      = -1;
static aos_event_t sync_event;

#define EVENT_DISCONN   0x00000001
#define EVENT_OTA       0x00000002
#define EVENT_ALERTOR   0x00000004

static void start_adv(void)
{
    ad_data_t ad[2] = {0};
    uint8_t flag = AD_FLAG_GENERAL | AD_FLAG_NO_BREDR;
    ad[0].type = AD_DATA_TYPE_FLAGS;
    ad[0].data = (uint8_t *)&flag;
    ad[0].len = 1;

    uint8_t uuid16_list[] = {0x12, 0x18, 0x0f, 0x18}; /* UUID_BAS, UUID_HIDS */
    ad[1].type = AD_DATA_TYPE_UUID16_ALL;
    ad[1].data = (uint8_t *)uuid16_list;
    ad[1].len = sizeof(uuid16_list);

    adv_param_t param = {
        ADV_IND,
        ad,
        NULL,
        BLE_ARRAY_NUM(ad),
        0,
        0x20,//ADV_FAST_INT_MIN_1,
        0x20,//ADV_FAST_INT_MAX_1,
    };

    int ret = ble_stack_adv_start(&param);

    if (ret) {
        LOGE(TAG, "adv start fail %d!", ret);
    } else {
        LOGE(TAG, "adv start!");
    }
}

static void is_paired_device(dev_addr_t *paired_addr, void *data)
{
    int ret = -1;
    connect_info_t conn_info = {0};

    if (g_conn_hanlde < 0 || paired_addr == NULL || data == NULL) {
        return;
    }

    ret = ble_stack_connect_info_get(g_conn_hanlde, &conn_info);
    if (ret == 0) {
        //LOGI(TAG, "conn %d, %s", conn_info.peer_addr.type, bt_hex_real(conn_info.peer_addr.val, 6));
        //LOGI(TAG, "paired %d, %s", paired_addr->type, bt_hex_real(paired_addr->val, 6));
        if (memcmp(&conn_info.peer_addr, paired_addr, sizeof(dev_addr_t)) == 0) {
            *(uint8_t *)data = 1;
        }
    }

}

static void conn_change(ble_event_en event, void *event_data)
{
    int ret = -1;
    evt_data_gap_conn_change_t *e = (evt_data_gap_conn_change_t *)event_data;

    if (e->connected == CONNECTED && e->err == 0) {
        LOGI(TAG, "Connected");
        g_conn_hanlde = e->conn_handle;
        uint8_t is_paired = 0;
        ret = ble_stack_paired_dev_foreach(is_paired_device, &is_paired);
        if (ret == 0) {
            LOGI(TAG, "is_paired = %d", is_paired);
        }
    } else {
        LOGI(TAG, "Disconnected err %d", e->err);
        g_conn_hanlde = -1;
        aos_event_set(&sync_event, EVENT_DISCONN, AOS_EVENT_OR);
    }
}

static int event_callback(ble_event_en event, void *event_data)
{
    switch (event) {
        case EVENT_GAP_CONN_CHANGE:
            conn_change(event, event_data);
            break;

        case EVENT_GAP_ADV_TIMEOUT:
            start_adv();
            break;

        default:
            break;
    }

    return 0;
}

static ble_event_cb_t ble_cb = {
    .callback = event_callback,
};

static void alertor_event_cb(alertor_state_en state)
{
    aos_event_set(&sync_event, EVENT_ALERTOR, AOS_EVENT_OR);
}

static void ota_event_cb(ota_state_en ota_state)
{
    aos_event_set(&sync_event, EVENT_OTA, AOS_EVENT_OR);
}


int main()
{
    int ret = 0;
    unsigned int event_flags;

    board_yoc_init();
    dev_addr_t addr = {DEV_ADDR_LE_RANDOM, DEVICE_ADDR};
    init_param_t init = {
        .dev_name = DEVICE_NAME,
        .dev_addr = &addr,
        .conn_num_max = 1,
    };

    aos_event_new(&sync_event, 0);

    LOGI(TAG, "Bluetooth Alertor demo!");

    ble_stack_init(&init);

    ble_stack_setting_load();
    //dev_addr_t addr = {0};
    //ble_stack_get_local_addr(&addr);
    //LOGI(TAG, "init ret = %d, %d, %s", ret, addr.type, bt_hex_real(addr.val, 6));

    ble_alertor_init(alertor_event_cb);

    bt_passkey_set(000000);

    ble_ota_init(ota_event_cb);

    ret = ble_stack_event_register(&ble_cb);

    if (ret) {
        LOGE(TAG, "register event faild");
        return -1;
    }

    start_adv();

    while (1) {
        ret = aos_event_get(&sync_event, 0xFFFFFFFF, AOS_EVENT_OR_CLEAR, &event_flags, AOS_WAIT_FOREVER);

        if (ret != 0) {
            LOGE(TAG, "aos_event_get error = %d", ret);
        }

        if ((event_flags & EVENT_OTA) == EVENT_OTA) {
            ble_ota_process();
        }

        if ((event_flags & EVENT_ALERTOR) == EVENT_ALERTOR) {
            ble_alertor_process();
        }

        if ((event_flags & EVENT_DISCONN) == EVENT_DISCONN) {
            start_adv();
        }
    }

    return 0;
}

